package com.zixuan.sina.config.security.filter;

import com.zixuan.sina.config.redis.RedisService;
import com.zixuan.sina.config.security.CommonUserDetailsService;
import com.zixuan.sina.config.security.LoginFaireHandler;
import com.zixuan.sina.utils.JwtUtils;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Data
@Component
public class CheckTokenFilter extends OncePerRequestFilter {

    @Value("${request.login.url}")
    private String loginUrl = "";
    @Value("${request.login.tokenKey}")
    private String tokenKey = "";
    @Resource
    JwtUtils jwtUtils;
    @Resource
    RedisService redisService;
    @Resource
    CommonUserDetailsService commonUserDetailsService;
    @Resource
    LoginFaireHandler loginFaireHandler;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        //判断请求地址 如果是登录地址就放行
        String url = request.getRequestURI();
        try {
            if (!url.equals(loginUrl)&&!url.equals("/api/user/add")) {//todo:此处放行登录地址和注册地址
                validateToken(request);//如果是登录
            }

        } catch (AuthenticationException e) {
            e.printStackTrace();
            loginFaireHandler.onAuthenticationFailure(request, response, e);
        }
        doFilter(request, response, filterChain);
    }
    private void validateToken(HttpServletRequest request) {
        //从headers和params里面获取token信息
        String token = request.getHeader("token");
        if (token == null) {
            token = request.getParameter("token");
            if (token == null) {
                throw new RuntimeException("未检测到token信息");
            }
        }
        String redisToken = redisService.get(tokenKey + token);
        if (redisToken == null) {
            throw new AccountExpiredException("token已过期");
        }
        //拿到token和redis里面的token比对
        if (!token.equals(redisToken)) {
            throw new AccountExpiredException("验证失败");
        }
        //从token中解析出username去查询数据库信息
        String username = jwtUtils.getUsernameFromToken(token);
        UserDetails userDetails = commonUserDetailsService.loadUserByUsername(username);
        if (userDetails == null) {
            throw new BadCredentialsException("token验证失败");
        }
        //查询数据库成功,创建身份对象
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
        authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
        //将token放入SpringSecurity上下文对象中去
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
    }
}
